/**
 * Spark创作引导对话服务
 * 负责管理引导式创作的完整流程
 */

import { AIService, AIServiceConfig } from '../ai/aiService'
import { AIResult } from '../ai/types'
import {
  SparkDialogState,
  DialogStep,
  DialogStepType,
  UserResponses,
  ArticleOutline,
  OutlineSection,
  OutlineSectionType,
  SectionStatus,
  SectionCountRule,
  SECTION_COUNT_RULES,
  SparkCreationData,
  ContentGenerationState,
  GenerationError,
  createDefaultDialogState,
  createDefaultArticleOutline,
  createDefaultOutlineSection,
  validateUserResponses,
  getNextPendingSection,
  calculateGenerationProgress
} from '../../types/spark'

/**
 * 对话流程配置
 */
interface DialogFlowConfig {
  steps: DialogStep[]
}

/**
 * Prompt模板配置
 */
interface PromptTemplates {
  topicClarification: string
  audienceStyle: string
  structurePlanning: string
  outlineGeneration: string
  sectionGeneration: string
}

export class SparkCreationService {
  private aiService: AIService
  private dialogFlow: DialogFlowConfig
  private prompts: PromptTemplates

  constructor(aiService: AIService) {
    this.aiService = aiService
    this.dialogFlow = this.createDialogFlow()
    this.prompts = this.createPromptTemplates()
  }

  /**
   * 开始Spark创作流程
   */
  async startSparkCreation(sparkInput: string): Promise<AIResult<DialogStep>> {
    console.log('[Spark服务] 开始创作流程', { sparkInput })

    // 创建对话状态
    const dialogState = createDefaultDialogState(sparkInput)
    
    // 生成第一个引导问题
    const firstStep = await this.processSparkInput(sparkInput)
    
    return firstStep
  }

  /**
   * 处理火花输入，生成第一个对话步骤
   */
  async processSparkInput(spark: string): Promise<AIResult<DialogStep>> {
    console.log('[Spark服务] 处理火花输入', { spark })

    // 分析火花输入，确定对话策略
    const analysisPrompt = this.prompts.topicClarification.replace('{spark}', spark)

    console.log('[Spark服务] 第一个问题的Prompt:')
    console.log('================== Prompt开始 ==================')
    console.log(analysisPrompt)
    console.log('================== Prompt结束 ==================')

    // 使用超时包装器
    const result = await this.callWithTimeout(
      this.aiService.continueWriting({
        fullText: analysisPrompt,
        cursorPosition: analysisPrompt.length
      }),
      60000, // 60秒超时
      '生成第一个问题'
    )

    if (!result.ok) {
      console.error('[Spark服务] AI调用失败:', result.error)
      return {
        ok: false,
        error: result.error
      }
    }

    console.log('[Spark服务] AI返回的第一个问题:')
    console.log('================== AI返回开始 ==================')
    console.log(result.data)
    console.log('================== AI返回结束 ==================')

    // 返回第一个对话步骤
    const firstStep: DialogStep = {
      type: DialogStepType.TOPIC_CLARIFICATION,
      question: result.data,
      isRequired: true,
      placeholder: '例如：介绍我们公司的新产品优势',
      helpText: '请尽量具体描述您想要表达的核心内容'
    }

    return {
      ok: true,
      data: firstStep
    }
  }

  /**
   * 处理用户回答，生成下一个对话步骤
   * @returns 返回更新后的对话状态和下一个步骤
   */
  async processUserResponse(
    dialogState: SparkDialogState,
    response: string
  ): Promise<AIResult<{
    dialogState: SparkDialogState
    nextStep: DialogStep | null
  }>> {
    console.log('[Spark服务] 处理用户回答', {
      currentStep: dialogState.currentStep,
      response
    })

    // 更新对话状态
    const updatedState = this.updateDialogState(dialogState, response)

    console.log('[Spark服务] 对话状态已更新', {
      currentStep: updatedState.currentStep,
      isCompleted: updatedState.isCompleted,
      responses: updatedState.responses
    })

    // 如果对话已完成，返回更新后的状态和null步骤
    if (updatedState.isCompleted) {
      return {
        ok: true,
        data: {
          dialogState: updatedState,
          nextStep: null
        }
      }
    }

    // 生成下一个对话步骤
    const nextStepResult = await this.generateNextDialogStep(updatedState)

    if (!nextStepResult.ok) {
      return nextStepResult as any
    }

    // 返回更新后的状态和下一个步骤
    return {
      ok: true,
      data: {
        dialogState: updatedState,
        nextStep: nextStepResult.data
      }
    }
  }

  /**
   * 生成文章大纲
   */
  async generateOutline(dialogState: SparkDialogState): Promise<AIResult<ArticleOutline>> {
    console.log('[Spark服务] 生成文章大纲 - 开始')
    console.log('[Spark服务] dialogState.responses:', JSON.stringify(dialogState.responses, null, 2))

    if (!validateUserResponses(dialogState.responses)) {
      console.error('[Spark服务] 用户回答验证失败:', dialogState.responses)
      return {
        ok: false,
        error: {
          code: 'INVALID_REQUEST' as any,
          message: '用户回答不完整，无法生成大纲'
        }
      }
    }

    // 构建大纲生成提示词
    const outlinePrompt = this.buildOutlinePrompt(dialogState.responses as UserResponses)

    console.log('[Spark服务] 生成的完整Prompt:')
    console.log('================== Prompt开始 ==================')
    console.log(outlinePrompt)
    console.log('================== Prompt结束 ==================')

    // 使用更大的maxTokens以确保JSON完整
    const sectionCount = dialogState.responses.sectionCount || 4
    const estimatedTokens = Math.max(1000, sectionCount * 150 + 200) // 每段约150 tokens + 200基础

    console.log('[Spark服务] 开始调用AI，预估tokens:', estimatedTokens)

    // 使用超时包装器，大纲生成可能需要更长时间
    const result = await this.callWithTimeout(
      this.aiService.continueWriting({
        fullText: outlinePrompt,
        cursorPosition: outlinePrompt.length,
        maxTokens: estimatedTokens
      }),
      90000, // 90秒超时
      '生成文章大纲'
    )

    if (!result.ok) {
      console.error('[Spark服务] AI调用失败:', result.error)
      return result as any
    }

    console.log('[Spark服务] AI返回的原始内容:')
    console.log('================== AI返回开始 ==================')
    console.log(result.data)
    console.log('================== AI返回结束 ==================')

    // 解析AI返回的大纲
    const outline = this.parseOutlineFromAI(result.data, dialogState.id)

    console.log('[Spark服务] 解析后的大纲:', JSON.stringify(outline, null, 2))

    return {
      ok: true,
      data: outline
    }
  }

  /**
   * 生成特定段落内容
   */
  async generateSectionContent(
    section: OutlineSection,
    outline: ArticleOutline,
    previousContent: string = ''
  ): Promise<AIResult<string>> {
    console.log('[Spark服务] 生成段落内容', {
      sectionId: section.id,
      sectionTitle: section.title
    })

    // 构建段落生成提示词
    const sectionPrompt = this.buildSectionPrompt(section, outline, previousContent)

    const result = await this.aiService.continueWriting({
      fullText: sectionPrompt,
      cursorPosition: sectionPrompt.length
    })

    if (!result.ok) {
      return result
    }

    // 清洗AI返回的内容，移除常见的引导语
    const cleanedContent = this.cleanGeneratedContent(result.data)

    console.log('[Spark服务] 段落内容生成完成', {
      sectionId: section.id,
      originalLength: result.data.length,
      cleanedLength: cleanedContent.length
    })

    return {
      ok: true,
      data: cleanedContent
    }
  }

  /**
   * 生成完整文章
   */
  async generateFullArticle(
    outline: ArticleOutline,
    onProgress?: (progress: number) => void
  ): Promise<AIResult<string>> {
    console.log('[Spark服务] 生成完整文章', { outlineId: outline.id })

    let fullContent = ''
    const totalSections = outline.sections.length
    
    // 按顺序生成每个段落
    for (let i = 0; i < outline.sections.length; i++) {
      const section = outline.sections[i]
      
      // 生成段落内容
      const result = await this.generateSectionContent(section, outline, fullContent)
      
      if (!result.ok) {
        return result
      }

      // 拼接内容
      fullContent += result.data + '\n\n'
      
      // 更新进度
      const progress = Math.round(((i + 1) / totalSections) * 100)
      onProgress?.(progress)
    }

    return {
      ok: true,
      data: fullContent.trim()
    }
  }

  /**
   * 创建对话流程配置
   */
  private createDialogFlow(): DialogFlowConfig {
    return {
      steps: [
        {
          type: DialogStepType.TOPIC_CLARIFICATION,
          question: '请详细描述您想要创作的内容主题',
          isRequired: true,
          placeholder: '例如：介绍我们公司的新产品优势',
          helpText: '请尽量具体描述您想要表达的核心内容'
        },
        {
          type: DialogStepType.AUDIENCE_STYLE,
          question: '请选择您的目标读者和写作风格',
          isRequired: true,
          options: ['专业人士', '普通大众', '行业专家', '学生群体'],
          helpText: '这将帮助我们调整语言风格和内容深度'
        },
        {
          type: DialogStepType.STRUCTURE_PLANNING,
          question: '您希望文章采用什么结构？',
          isRequired: true,
          options: ['总分总结构', '问题解决型', '对比分析型', '时间顺序型'],
          helpText: '选择合适的结构能让文章更有逻辑性'
        },
        {
          type: DialogStepType.OUTLINE_GENERATION,
          question: '正在为您生成文章大纲...',
          isRequired: false,
          helpText: '基于您的回答，我们将生成详细的文章大纲'
        }
      ]
    }
  }

  /**
   * 创建Prompt模板
   */
  private createPromptTemplates(): PromptTemplates {
    return {
      topicClarification: `你是专业的写作顾问。用户提供了创作灵感：

"{spark}"

请仔细分析这段创作灵感，然后：

1. 首先理解用户想要创作什么内容
2. 识别出用户已经明确表达的信息（主题、目的、受众、风格等）
3. 找出仍然模糊或需要补充的关键信息
4. 针对缺失的部分，提出1-2个具体、针对性的问题

重要要求：
- 绝对不要询问用户已经在灵感中明确说过的内容
- 问题必须紧扣用户的具体灵感，而不是通用问题
- 避免"您的核心主题是什么"这类通用问题
- 在问题中体现你对用户灵感的理解
- 用友好、专业的语气

回答格式示例：
我理解您想要[简短总结用户的创作意图]。为了帮您更好地展开这个主题，想请教几个问题：[基于用户灵感的针对性问题1]？[针对性问题2]？`,

      audienceStyle: `基于用户确认的主题：{topic}
创作目的：{purpose}

请继续引导用户确定：
1. 目标读者是谁？（专业人士、普通大众、特定行业等）
2. 希望采用什么样的写作风格？（正式、轻松、专业、亲切等）
3. 文章的理想长度是多少？（短文300字、中篇800字、长文1500字等）

请提供具体的选项让用户选择。`,

      structurePlanning: `基于已确认的信息：
主题：{topic}
目的：{purpose}
读者：{audience}
风格：{tone}
长度：{length}

请帮助用户梳理文章结构：
1. 这篇文章适合采用什么结构？（总分总、问题解决、时间顺序等）
2. 需要重点阐述哪些核心观点？
3. 有哪些支撑材料或例子？

请给出具体的结构建议。`,

      outlineGeneration: `作为专业的内容规划师，请根据以下信息生成详细的文章大纲：

创作信息：
- 主题：{topic}
- 目的：{purpose}
- 读者：{audience}
- 风格：{tone}
- 总字数：严格控制在 {totalWords}±10% 字
- 段落数量：必须恰好 {sectionCount} 段
- 核心观点：{keyPoints}

段落配置规则：
1. 总段落数必须等于 {sectionCount}
2. 所有段落预计字数之和应接近 {totalWords} 字
3. 段落类型分配：
   - 第1段：引言（intro），约 {introLength} 字
   - 第2至第{bodyEnd}段：正文（body），每段约 {bodyLength} 字
   - 第{sectionCount}段：结论（conclusion），约 {conclusionLength} 字

质量要求：
- 确保逻辑清晰、结构合理
- 符合目标读者的阅读习惯
- 每个段落都有明确的主题和要点

请以JSON格式返回大纲：
{
  "title": "文章标题",
  "sections": [
    {
      "title": "段落标题",
      "type": "intro|body|conclusion",
      "description": "段落描述",
      "keyPoints": ["要点1", "要点2"],
      "estimatedLength": 200
    }
  ]
}`,

      sectionGeneration: `作为专业的内容创作者，请根据以下信息生成文章段落：

文章背景：
- 整体主题：{articleTopic}
- 目标读者：{audience}
- 写作风格：{tone}

当前段落要求：
- 段落标题：{sectionTitle}
- 段落类型：{sectionType}
- 主要内容点：{keyPoints}
- 目标字数：{targetLength}

已生成的前文内容：
{previousContent}

要求：
1. 内容与前文保持连贯性
2. 符合段落主题和要求
3. 语言风格一致
4. 字数控制在目标范围内
5. 内容丰富、有说服力
6. 直接输出段落正文内容，不要添加"继续写"、"以下是"等引导语

段落正文内容：`
    }
  }

  /**
   * 更新对话状态
   */
  private updateDialogState(
    dialogState: SparkDialogState,
    response: string
  ): SparkDialogState {
    const updatedState = { ...dialogState }
    const currentStepType = this.dialogFlow.steps[dialogState.currentStep]?.type

    // 根据当前步骤类型保存用户回答
    switch (currentStepType) {
      case DialogStepType.TOPIC_CLARIFICATION:
        updatedState.responses.topic = response
        // 推断创作目的（从主题中提取关键词）
        updatedState.responses.purpose = this.inferPurpose(response)
        break

      case DialogStepType.AUDIENCE_STYLE:
        // 处理所有4个受众选项
        if (response.includes('专业人士')) {
          updatedState.responses.audience = '专业人士'
          updatedState.responses.tone = '专业正式'
        } else if (response.includes('普通大众')) {
          updatedState.responses.audience = '普通大众'
          updatedState.responses.tone = '轻松易懂'
        } else if (response.includes('行业专家')) {
          updatedState.responses.audience = '行业专家'
          updatedState.responses.tone = '深度专业'
        } else if (response.includes('学生群体')) {
          updatedState.responses.audience = '学生群体'
          updatedState.responses.tone = '通俗易懂'
        } else {
          // 兜底：直接使用用户的回答
          updatedState.responses.audience = response
          updatedState.responses.tone = '适中'
        }

        // 解析字数（支持多种格式）
        // 格式1: "文章字数800字"
        // 格式2: "800字"
        // 格式3: "字数：800"
        const wordsMatch = response.match(/(?:文章字数|字数[:：]?\s*)?(\d+)\s*字/)
        const totalWords = wordsMatch ? parseInt(wordsMatch[1]) : 800
        updatedState.responses.totalWords = totalWords

        // 解析段落数
        const sectionsMatch = response.match(/(?:分|共)?\s*(\d+)\s*段/)
        let sectionCount = sectionsMatch ? parseInt(sectionsMatch[1]) : 0

        // 如果没有指定段落数，根据字数推荐
        if (!sectionCount) {
          const rule = this.getSectionCountRule(totalWords)
          sectionCount = rule.recommendedSections
        }

        updatedState.responses.sectionCount = sectionCount

        console.log('[Spark服务] 解析篇幅配置:', {
          totalWords,
          sectionCount,
          audience: updatedState.responses.audience
        })
        break

      case DialogStepType.STRUCTURE_PLANNING:
        updatedState.responses.structure = response
        updatedState.responses.keyPoints = this.extractKeyPoints(response)
        break
    }

    // 移动到下一步
    updatedState.currentStep += 1
    updatedState.updatedAt = new Date()

    // 检查是否完成
    if (updatedState.currentStep >= this.dialogFlow.steps.length - 1) {
      updatedState.isCompleted = true
    }

    return updatedState
  }

  /**
   * 从主题推断创作目的
   */
  private inferPurpose(topic: string): string {
    // 根据关键词推断创作目的
    if (topic.match(/介绍|展示|说明|阐述/)) {
      return '通知说明'
    } else if (topic.match(/推广|宣传|营销|广告/)) {
      return '宣传推广'
    } else if (topic.match(/分析|研究|探讨|论述/)) {
      return '分析论述'
    } else if (topic.match(/教|学|指导|培训/)) {
      return '教育培训'
    } else if (topic.match(/故事|经历|体验/)) {
      return '叙事分享'
    } else {
      return '信息传达'  // 默认目的
    }
  }

  /**
   * 清洗AI生成的内容，移除引导性文本和多余换行
   */
  private cleanGeneratedContent(content: string): string {
    // 移除常见的引导语模式
    const patterns = [
      /^继续写[：:]\s*/,           // "继续写："
      /^以下是[^：:]*[：:]\s*/,     // "以下是...："
      /^好的[，,][^：:]*[：:]\s*/,   // "好的，...："
      /^下面[是我将][^：:]*[：:]\s*/, // "下面是..."
      /^让我[^：:]*[：:]\s*/,       // "让我..."
      /^请看[^：:]*[：:]\s*/,       // "请看..."
      /^这里[是有][^：:]*[：:]\s*/   // "这里是..."
    ]

    let cleaned = content.trim()

    // 依次尝试移除匹配的模式
    for (const pattern of patterns) {
      cleaned = cleaned.replace(pattern, '')
    }

    // 移除首行如果只是单独的标点或短引导语（3个字以内）
    const lines = cleaned.split('\n')
    if (lines.length > 1 && lines[0].length <= 3 && /^[：:，,。！？\s]*$/.test(lines[0])) {
      cleaned = lines.slice(1).join('\n')
    }

    // 清理多余的换行（连续3个以上换行符替换为2个）
    cleaned = cleaned.replace(/\n{3,}/g, '\n\n')

    // 清理首尾空白
    cleaned = cleaned.trim()

    // 如果内容开头有独立的标题行（只有标题，无其他内容），保留它
    // 这样后续的 mergeFullArticle 可以正确检测和处理

    return cleaned
  }

  /**
   * 生成下一个对话步骤
   */
  private async generateNextDialogStep(
    dialogState: SparkDialogState
  ): Promise<AIResult<DialogStep>> {
    const stepIndex = dialogState.currentStep
    const stepTemplate = this.dialogFlow.steps[stepIndex]

    if (!stepTemplate) {
      return {
        ok: false,
        error: {
          code: 'INVALID_REQUEST' as any,
          message: '无效的对话步骤'
        }
      }
    }

    // 返回预定义的步骤
    return {
      ok: true,
      data: stepTemplate
    }
  }

  /**
   * 构建大纲生成提示词
   */
  private buildOutlinePrompt(responses: UserResponses): string {
    // 提供更好的默认值
    const topic = responses.topic || '未指定主题'
    const purpose = responses.purpose || '提供有价值的信息'
    const audience = responses.audience || '一般读者'
    const tone = responses.tone || '专业友好'
    const totalWords = responses.totalWords || 800
    const sectionCount = responses.sectionCount || 4
    const keyPoints = responses.keyPoints?.join(', ') || ''

    // 计算每段建议字数
    const sectionLengths = this.calculateSectionLengths(totalWords, sectionCount)
    const introLength = sectionLengths[0]
    const bodyLength = sectionLengths[1] || 200
    const conclusionLength = sectionLengths[sectionLengths.length - 1]
    const bodyEnd = sectionCount - 1

    return this.prompts.outlineGeneration
      .replace('{topic}', topic)
      .replace('{purpose}', purpose)
      .replace('{audience}', audience)
      .replace('{tone}', tone)
      .replace(/{totalWords}/g, totalWords.toString())
      .replace(/{sectionCount}/g, sectionCount.toString())
      .replace('{keyPoints}', keyPoints)
      .replace('{introLength}', introLength.toString())
      .replace('{bodyLength}', bodyLength.toString())
      .replace('{bodyEnd}', bodyEnd.toString())
      .replace('{conclusionLength}', conclusionLength.toString())
  }

  /**
   * 构建段落生成提示词
   */
  private buildSectionPrompt(
    section: OutlineSection,
    outline: ArticleOutline,
    previousContent: string
  ): string {
    return this.prompts.sectionGeneration
      .replace('{articleTopic}', outline.title)
      .replace('{audience}', '目标读者')
      .replace('{tone}', '专业风格')
      .replace('{sectionTitle}', section.title)
      .replace('{sectionType}', section.type)
      .replace('{keyPoints}', section.keyPoints.join(', '))
      .replace('{targetLength}', section.estimatedLength.toString())
      .replace('{previousContent}', previousContent)
  }

  /**
   * 从AI返回内容解析大纲
   */
  private parseOutlineFromAI(aiContent: string, sparkId: string): ArticleOutline {
    try {
      // 清理markdown代码块标记
      let cleanContent = aiContent.trim()

      // 移除 ```json 和 ``` 标记
      if (cleanContent.startsWith('```json')) {
        cleanContent = cleanContent.replace(/^```json\s*\n/, '')
      } else if (cleanContent.startsWith('```')) {
        cleanContent = cleanContent.replace(/^```\s*\n/, '')
      }

      if (cleanContent.endsWith('```')) {
        cleanContent = cleanContent.replace(/\n```\s*$/, '')
      }

      // 尝试修复不完整的JSON
      cleanContent = this.fixIncompleteJSON(cleanContent)

      // 尝试解析JSON格式的大纲
      const parsed = JSON.parse(cleanContent)

      const sections: OutlineSection[] = parsed.sections.map((section: any, index: number) => ({
        id: `section_${Date.now()}_${index}`,
        title: section.title,
        type: this.mapSectionType(section.type),
        description: section.description || '',
        keyPoints: section.keyPoints || [],
        estimatedLength: section.estimatedLength || 200,
        status: SectionStatus.PENDING,
        order: index
      }))

      return {
        id: `outline_${Date.now()}`,
        title: parsed.title || '新文章',
        sections,
        totalEstimatedLength: sections.reduce((sum, s) => sum + s.estimatedLength, 0),
        sparkId,
        createdAt: new Date(),
        updatedAt: new Date()
      }
    } catch (error) {
      // 如果JSON解析失败，生成默认大纲
      console.warn('[Spark服务] 大纲解析失败，使用默认大纲', error)
      return createDefaultArticleOutline('新文章', sparkId)
    }
  }

  /**
   * 尝试修复不完整的JSON
   */
  private fixIncompleteJSON(jsonStr: string): string {
    let fixed = jsonStr.trim()

    // 如果JSON以逗号结尾(意味着还有内容没生成完),尝试移除最后不完整的项
    if (fixed.endsWith(',')) {
      // 找到最后一个完整的对象
      const lastCompleteObjectIndex = fixed.lastIndexOf('}')
      if (lastCompleteObjectIndex > 0) {
        fixed = fixed.substring(0, lastCompleteObjectIndex + 1)
      }
    }

    // 检查并补全缺失的闭合括号
    const openBraces = (fixed.match(/{/g) || []).length
    const closeBraces = (fixed.match(/}/g) || []).length
    const openBrackets = (fixed.match(/\[/g) || []).length
    const closeBrackets = (fixed.match(/\]/g) || []).length

    // 补全缺失的}
    for (let i = 0; i < openBraces - closeBraces; i++) {
      fixed += '\n}'
    }

    // 补全缺失的]
    for (let i = 0; i < openBrackets - closeBrackets; i++) {
      fixed += '\n]'
    }

    // 移除最后不完整的属性(如果有)
    // 例如: "type": 或 "description":
    fixed = fixed.replace(/,?\s*"[^"]+"\s*:\s*$/, '')

    // 移除最后不完整的数组项
    fixed = fixed.replace(/,?\s*{\s*$/, '')

    return fixed
  }

  /**
   * 映射段落类型
   */
  private mapSectionType(type: string): OutlineSectionType {
    switch (type?.toLowerCase()) {
      case 'intro':
      case 'introduction':
        return OutlineSectionType.INTRO
      case 'conclusion':
      case 'summary':
        return OutlineSectionType.CONCLUSION
      default:
        return OutlineSectionType.BODY
    }
  }

  /**
   * 从用户回答中提取关键要点
   */
  private extractKeyPoints(response: string): string[] {
    // 简单的关键要点提取逻辑
    const sentences = response.split(/[。！？\n]/).filter(s => s.trim().length > 5)
    return sentences.slice(0, 3) // 最多取3个要点
  }

  /**
   * 根据字数获取段落数配置规则
   */
  private getSectionCountRule(words: number): SectionCountRule {
    return SECTION_COUNT_RULES.find(
      rule => words >= rule.minWords && words <= rule.maxWords
    ) || SECTION_COUNT_RULES[SECTION_COUNT_RULES.length - 1]
  }

  /**
   * 根据文章内容生成标题
   * @param fullContent 完整的文章内容（Markdown格式）
   * @param dialogState 对话状态（包含主题、受众等信息）
   * @returns 生成的文章标题
   */
  async generateArticleTitle(
    fullContent: string,
    dialogState: SparkDialogState
  ): Promise<AIResult<string>> {
    console.log('[Spark服务] 开始生成文章标题')

    const responses = dialogState.responses

    // 构建标题生成Prompt
    const titlePrompt = `你是一位专业的内容编辑，请为以下文章生成一个简洁有力的标题。

【文章信息】
主题：${responses.topic || '未指定'}
目的：${responses.purpose || '信息传达'}
目标受众：${responses.audience || '普通大众'}

【文章内容】
${fullContent.substring(0, 1000)}${fullContent.length > 1000 ? '...' : ''}

【标题要求】
1. 简洁有力，8-20个字
2. 准确概括文章主题和核心价值
3. 符合目标受众的阅读习惯
4. 具有吸引力，能激发阅读兴趣
5. 直接输出标题文本，不要加引号或其他符号

请生成标题：`

    console.log('[Spark服务] 标题生成Prompt:')
    console.log('================== Prompt开始 ==================')
    console.log(titlePrompt)
    console.log('================== Prompt结束 ==================')

    const result = await this.aiService.continueWriting({
      fullText: titlePrompt,
      cursorPosition: titlePrompt.length
    })

    if (!result.ok) {
      console.error('[Spark服务] 标题生成失败:', result.error)
      return {
        ok: false,
        error: result.error
      }
    }

    // 清理AI返回的标题（移除引号、换行等）
    let title = result.data.trim()
    title = title.replace(/^["'「『]|["'」』]$/g, '') // 移除首尾引号
    title = title.replace(/\n.*/g, '') // 只保留第一行
    title = title.substring(0, 50) // 限制最大长度

    console.log('[Spark服务] AI生成的标题:', title)

    return {
      ok: true,
      data: title
    }
  }

  /**
   * 智能分配每段字数
   * @param totalWords 总字数
   * @param sectionCount 段落数
   * @returns 每段的预估字数数组
   */
  private calculateSectionLengths(
    totalWords: number,
    sectionCount: number
  ): number[] {
    if (sectionCount < 2) {
      return [totalWords]
    }

    // 引言和结论各占15-20%
    const introLength = Math.round(totalWords * 0.175)
    const conclusionLength = Math.round(totalWords * 0.175)

    // 正文段落平均分配剩余字数
    const remainingWords = totalWords - introLength - conclusionLength
    const bodySectionCount = sectionCount - 2
    const avgBodyLength = Math.round(remainingWords / bodySectionCount)

    // 构建结果数组
    const lengths: number[] = [introLength]
    for (let i = 0; i < bodySectionCount; i++) {
      lengths.push(avgBodyLength)
    }
    lengths.push(conclusionLength)

    return lengths
  }

  /**
   * 带超时的AI调用包装器
   * @param promise AI调用Promise
   * @param timeoutMs 超时时间（毫秒）
   * @param operation 操作名称（用于日志）
   * @returns AI调用结果
   */
  private async callWithTimeout<T>(
    promise: Promise<AIResult<T>>,
    timeoutMs: number,
    operation: string
  ): Promise<AIResult<T>> {
    console.log(`[Spark服务] ${operation} - 设置${timeoutMs/1000}秒超时`)

    return Promise.race([
      promise,
      new Promise<AIResult<T>>((_, reject) => {
        setTimeout(() => {
          console.error(`[Spark服务] ${operation} - 超时`)
          reject({
            ok: false,
            error: {
              code: 'TIMEOUT' as any,
              message: `操作超时（${timeoutMs/1000}秒）：${operation}。请检查网络连接或稍后重试。`
            }
          })
        }, timeoutMs)
      })
    ]).catch(error => {
      // 捕获所有错误，包括超时错误
      if (error.ok === false) {
        return error
      }
      return {
        ok: false,
        error: {
          code: 'UNKNOWN' as any,
          message: error.message || `${operation}失败`
        }
      }
    })
  }
}